home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
gnuish
/
swalibas
/
sw_popen.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-09-10
|
7KB
|
313 lines
/* sw_popen.c - popen () and pclose () with swapping.
Copyright (C) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
This file is part of SWAPLIB (the library), a library for efficient
execution of child processes under MS-DOS.
The library is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
The library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the library; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Header: e:/gnu/swaplib/RCS/sw_popen.c'v 0.9 90/09/09 21:44:07 tho Stable $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <fcntl.h>
#include "swaplib.h"
extern void *xmalloc (size_t size);
/* We do not perform an extensive error check, but well-formed
MODE strings will be recognized properly. */
#define BIN_MODE(p) (strchr ((p).mode, 'b') != NULL)
#define TXT_MODE(p) (strchr ((p).mode, 't') != NULL)
#define WR_MODE(p) (strchr ((p).mode, 'w') != NULL)
#define RD_MODE(p) (strchr ((p).mode, 'r') != NULL)
#define APP_MODE(p) (strchr ((p).mode, 'a') != NULL)
#define RDWR_MODE(p) (strchr ((p).mode, '+') != NULL)
/* This is a very simple way to mark a pipe as closed or available
not open in any mode! */
#define CLOSED(p) ((p).mode == NULL)
#define AVAIL(p) ((p).mode == NULL)
#define MAX_PIPES (_NFILE - 3)
struct pipe
{
/* The stream for this pipe (that's what the caller will use). */
FILE *file;
/* Are we reading or writing, or is it closed? */
char *mode;
/* The name of the temporary file for this pipe. */
char *name;
/* The command to pipe in to or out from. */
char *cmd;
/* The returncode of the above command. */
int rc;
};
typedef struct pipe PIPE;
static PIPE *pipes = NULL;
static FILE *popen_write (int ph);
static FILE *popen_read (int ph);
static int pclose_write (int ph);
static int pclose_read (int ph);
static int init_pipes (void);
static void cleanup_pipes (void);
/* Open a pipe to or from a shell COMMAND. Returns a stdio stream. */
FILE *
swap_popen (char *command, char *mode)
{
int i;
/* Raw check of arguments. */
if (!command || !mode || strchr (mode, 'a') || strchr (mode, '+'))
{
errno = EINVAL;
return NULL;
}
/* Have we had a pipe already? If not, perform the necessary
initializations. */
if (!pipes)
if (init_pipes () != 0)
return NULL;
for (i = 0; i < MAX_PIPES; i++)
{
/* Scan the list of pipes for an available one. */
if (AVAIL (pipes[i]))
{
/* Initialize the data structure for this pipe. */
pipes[i].cmd = command;
pipes[i].mode = mode;
pipes[i].name = swap_mktmpname ("pi");
if (!pipes[i].name)
return NULL;
/* Actually open the pipe. */
if (WR_MODE (pipes[i]))
return popen_write (i);
else if (RD_MODE (pipes[i]))
return popen_read (i);
else
{
free (pipes[i].name);
return NULL;
}
}
}
/* Failed. */
errno = EAGAIN;
return NULL;
}
/* Close a pipe to or from a shell command. Returns the exit code
of the command. */
int
swap_pclose (FILE *pipe_file)
{
int i;
for (i = 0; i < MAX_PIPES; i++)
{
/* Scan the list of pipes for the stdio stream which uniquely
identifies the pipe. */
if (pipes[i].file == pipe_file)
{
/* Actually close the pipe. */
if (WR_MODE (pipes[i]))
return pclose_write (i);
else if (RD_MODE (pipes[i]))
return pclose_read (i);
else
{
errno = EBADF;
return -1;
}
}
}
/* Failed. */
errno = EBADF;
return -1;
}
int
init_pipes (void)
{
int i;
pipes = (PIPE *) xmalloc (MAX_PIPES * sizeof (PIPE));
for (i = 0; i < MAX_PIPES; i++)
{
pipes[i].mode = NULL;
pipes[i].file = NULL;
}
/* Make sure that all pipes will be closed at exit ().
This is non trivial under MS-DOS, since we will have to
run the command that we wrote to at this time! */
return atexit (cleanup_pipes);
}
void
cleanup_pipes (void)
{
int i;
for (i = 0; i < MAX_PIPES; i++)
{
if (RD_MODE (pipes[i]))
pclose_read (i);
else if (WR_MODE (pipes[i]))
pclose_write (i);
}
}
FILE *
popen_write (int ph)
{
/* At the moment, all we need is a stdio stream to write to. */
return (pipes[ph].file = fopen (pipes[ph].name, pipes[ph].mode));
}
FILE *
popen_read (int ph)
{
int save_stdout = dup (1);
FILE *pf = fopen (pipes[ph].name, BIN_MODE (pipes[ph]) ? "wb" : "w");
dup2 (fileno (pf), 1);
pipes[ph].rc = swap_system (pipes[ph].cmd);
dup2 (save_stdout, 1);
close (save_stdout);
fclose (pf);
return (pipes[ph].file = fopen (pipes[ph].name, pipes[ph].mode));
}
int
pclose_write (int ph)
{
int rc;
int save_stdin;
FILE *pf;
/* Close the stream (we're done writing...). */
fclose (pipes[ph].file);
/* Get a copy of our standard input (in order to reclaim it
after redirections.) */
save_stdin = dup (0);
/* Reopen the temporary file, but this time for reading. And `dup'
it to standard input (descriptor 0). */
pf = fopen (pipes[ph].name, BIN_MODE (pipes[ph]) ? "rb" : "r");
dup2 (fileno (pf), 0);
/* Execute the command. (With standard input redirected from our
pipe (i.e. temporary file). */
rc = swap_system (pipes[ph].cmd);
/* `dup` the old standard input back to file descriptor 0, close
the temporary file, and return the handle used to save the old
standard input to the system. */
dup2 (save_stdin, 0);
close (save_stdin);
fclose (pf);
/* Clean up and mark the pipe as available. */
pipes[ph].mode = NULL;
pipes[ph].file = NULL;
unlink (pipes[ph].name);
free (pipes[ph].name);
return rc;
}
int
pclose_read (int ph)
{
fclose (pipes[ph].file);
pipes[ph].mode = NULL;
pipes[ph].file = NULL;
unlink (pipes[ph].name);
free (pipes[ph].name);
return pipes[ph].rc;
}
/*
* Local Variables:
* mode:C
* ChangeLog:ChangeLog
* compile-command:make
* End:
*/